<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2016-10-09
 * Time: 18:41
 */

namespace iBrand\Shop\Server\Http\Controllers;


use Carbon\Carbon;
use iBrand\Component\Payment\Contracts\PaymentChargeContract;
use iBrand\Server\Http\Controllers\Controller;

use iBrand\Shop\Core\Models\Order;

use iBrand\Component\Order\Models\OrderItem;
use iBrand\Component\Point\Model\Point;
use iBrand\Component\Point\Repository\PointRepository;
use iBrand\Component\Order\Processor\OrderProcessor;
use iBrand\Component\Order\Repositories\OrderRepository;
use iBrand\Component\Payment\Models\Payment;
use iBrand\Component\Product\Models\Goods;
use iBrand\Component\Product\Models\Product;
use iBrand\Component\Payment\Services\PaymentService;
use iBrand\Component\User\Models\User;
use iBrand\Component\User\Models\Group;
use iBrand\Shop\Core\Models\ShopOrder;
use iBrand\Shop\Core\Processor\ShopOrderProcessor;
use iBrand\Store\Frontend\Services\UserService;
use QrCode;
use DB;
use iBrand\Shop\Core\Repositories\ShopOrderRepository;
use iBrand\Shop\Core\Repositories\BalanceRepository;
use iBrand\Shop\Core\Models\Balance;
use Illuminate\Http\Request;
use Validator;
use iBrand\Sms\Facade as Sms;

class PaymentController extends Controller
{
    private $payment;
    private $orderRepository;
    private $orderProcessor;
    private $point;
    protected $userService;
    protected $shopOrderRepository;
    protected $balanceRepository;
    protected $shopOrderProcessor;
    private $charge;

    public function __construct(PaymentService $paymentService
        , OrderRepository $orderRepository
        , OrderProcessor $orderProcessor
        , PointRepository $pointRepository
        , UserService $userService
        , ShopOrderRepository $shopOrderRepository
        , BalanceRepository $balanceRepository
        , ShopOrderProcessor $shopOrderProcessor
        , PaymentChargeContract $chargeContract
    )
    {
        $this->payment = $paymentService;
        $this->orderRepository = $orderRepository;
        $this->orderProcessor = $orderProcessor;
        $this->point = $pointRepository;
        $this->userService = $userService;
        $this->shopOrderRepository = $shopOrderRepository;
        $this->balanceRepository = $balanceRepository;
        $this->shopOrderProcessor = $shopOrderProcessor;
        $this->charge = $chargeContract;
    }


    public function createCharge()
    {

        $clerk = auth('clerk')->user();

        $order_no = request('order_no');

        if (!$order_no || !$order = Order::where('order_no', $order_no)->first()) {
            return $this->api([], false, 402, '订单不存在');
        }

        if (!$this->shopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
            return $this->api([], false, 400, '无权操作此订单');
        };

        $user = User::find($order->user_id);

        if ($user->id !== $order->user_id || $order->status !== Order::STATUS_NEW) {

            return $this->api([], false, 402, '请勿扰重复提交订单支付');
        }

        if ($order->status == Order::STATUS_INVALID) {
            return $this->api([], false, 400, '无法支付');
        }

        $total = $order->total;
        if ($order->type == Order::TYPE_SHOP AND $refund = $order->orderRefund) {
            $total = $refund->difference_amount;
        }

        if (request('channel') == 'wx_pub_qr') {
            $charge = $this->charge->createCharge(
                $user->id
                , request('channel')
                , 'order'
                , $order_no
                , $total
                , $order->getSubject()
                , $order->getSubject()
                , request()->getClientIp()
                , request('openid')
                , request('extra')
            );
            return $this->api($charge, true, 200, '');
        }


        return $this->api([], false, 400, '');


    }

    public function webhooks()
    {
        $raw_data = file_get_contents('php://input');

        $result = $this->verifyPing($raw_data);

        if ($result === 1) {
            $event = json_decode($raw_data, true);

            if ($event['type'] == 'charge.succeeded') {

                $charge = $event['data']['object'];

                if ($charge['paid']) {  //如果支付成功

                    //$this->paymentService->paySuccess($charge);
                    $this->payment->paySuccess($charge);
                }

                http_response_code(200); // PHP 5.4 or greater
                exit;
            } elseif ($event['type'] == 'refund.succeeded') {
                $refund = $event['data']['object'];
                // ...
                http_response_code(200); // PHP 5.4 or greater
                exit;
            } else {
                /**
                 * 其它类型 ...
                 * - summary.daily.available
                 * - summary.weekly.available
                 * - summary.monthly.available
                 * - transfer.succeeded
                 * - red_envelope.sent
                 * - red_envelope.received
                 * ...
                 */
                //http_response_code(200);

                // 异常时返回非 2xx 的返回码
                http_response_code(400);
                exit;
            }
        } else {
            return $this->verifyPingFail($result);
        }
    }

    protected function verifyPing($rawData)
    {
        $headers = \Pingpp\Util\Util::getRequestHeaders();
        $signature = isset($headers['X-Pingplusplus-Signature']) ? $headers['X-Pingplusplus-Signature'] : NULL;
        $pulicKeyContents = $this->getPublicKey();
        return openssl_verify($rawData, base64_decode($signature), $pulicKeyContents, 'sha256');
    }

    protected function verifyPingFail($result)
    {
        if ($result === 0) {
            http_response_code(400);
            echo 'verification failed';
            exit;
        }
        http_response_code(400);
        echo 'verification error:' . $result;
        exit;
    }

    public function paidSuccess()
    {

        $order_no = request('order_no');
        $clerk = auth('clerk')->user();

        /*if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
            return $this->api( [],false, 402, '订单不存在');
        }*/

        if (!$order_no || !$order = Order::where('order_no', $order_no)->first()) {
            return $this->api([], false, 402, '订单不存在');
        }

        if (!$this->shopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
            return $this->api([], false, 400, '无权操作此订单');
        };

        $user = User::find($order->user_id);

        if ($user->cant('update', $order)) {
            return $this->api([], false, 402, '你没有权利操作此订单');
        }

        if (settings('pingxx_pay_scene') == 'test') {

            $payment = new Payment(['order_id' => $order->id, 'channel' => request('channel') ? request('channel') : 'test',
                'amount' => request('amount') ? request('amount') : $order->total, 'status' => Payment::STATUS_COMPLETED
                , 'paid_at' => Carbon::now()]);

            $order->payments()->save($payment);

            $this->orderProcessor->process($order);
        }

        if ($order->status == Order::STATUS_PAY) {

            $pointInfo = $this->getPointInfo($order);

            $userGroup = $this->userService->getUserGroupInfo($user);

            return $this->api(
                ['order' => $order, 'pointInfo' => $pointInfo,
                    'userGroup' => $userGroup], true);
        }

        if (settings('order_price_protection_enabled')) {
            return $this->api(['order' => $order], false, 204, '该商品暂时无法购买，如需帮助请与在线客服取得联系');
        } else {
            return $this->api(['order' => $order], false, 204, '支付失败');
        }

    }

    private function getPublicKey()
    {
        if ($publicKey = settings('pingxx_rsa_public_key')) {
            return $publicKey;
        } else {
            return file_get_contents(public_path() . '/pingpp_rsa_public_key.pem');
        }
    }


    private function userPoint($id, $type = null)
    {
        $point = $this->point->getSumPoint($id, $type);
        $pointValid = $this->point->getSumPointValid($id, $type);
        $pointOverValid = $this->point->getSumPointOverValid($id, $type);

        return $data = [
            'point' => $point,
            'pointValid' => $pointValid,
            'pointOverValid' => $pointOverValid,
        ];

    }

    private function getPointInfo($order)
    {
        $pointUsed = Point::where([
            'item_type' => 'iBrand\Component\Order\Models\Order',
            'item_id' => $order->id
        ])->first();

        $pointUsed = $pointUsed ? $pointUsed->value : 0;
        $pointAdded = 0;

        $items = $order->getItems();

        foreach ($items as $item) {
            if ($point = Point::where('item_id', $item->id)
                ->where('item_type', OrderItem::class)
                ->where('user_id', $order->user_id)->first()
            ) {
                $pointAdded += $point->value;
            }
        }
        $pointTotal = $this->point->getSumPointValid($order->user_id, 'default');
        return [
            'pointUsed' => $pointUsed,
            'pointAdded' => $pointAdded,
            'pointTotal' => $pointTotal
        ];
    }

    public function getWxPayQRCode()
    {
        $url = request('url');
        if (!empty($url)) {
            $code = QrCode::size(198)->margin(0)->generate($url);
            $pat = "/<svg.*>.*<\/svg>/";
            preg_match_all($pat, $code, $res);
            return $this->api(['code' => $res[0][0]], true, 200, '');
        }
        return $this->api([], false, 400, '');
    }

    public function checkOrderPay()
    {
        $clerk = auth('clerk')->user();
        $order_no = request('order_no');

        if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
            return $this->api([], false, 402, '订单不存在');
        }

        if (!$this->shopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
            return $this->api([], false, 400, '无权操作此订单');
        };

        $user = User::find($order->user_id);

        if ($user->cant('update', $order)) {
            return $this->api([], false, 402, '你没有权利操作此订单');
        }

        if ($order->status == Order::STATUS_PAY) {
            $pointInfo = $this->getPointInfo($order);
            if ($order->type == Order::TYPE_SHOP) {
                $this->shopOrderProcessor->completeOrder($order);
            }
            return $this->api(['order' => $order, 'pointInfo' => $pointInfo], true);
        }
        return $this->api(['order' => $order], false, 400, '');
    }


    public function amountConfirmArrival(Request $request)
    {

        $order_no = request('order_no');

        $clerk = auth('clerk')->user();

        $channel = request('channel');

        if (!$channel || !in_array($channel, ['pop_cash_pay', 'cash_pay', 'ali_scan_pay', 'balance'])) {
            return $this->api([], false, 402, '支付方式错误');
        }
        if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
            return $this->api([], false, 402, '订单不存在');
        }

        if (!$this->shopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
            return $this->api([], false, 400, '无权操作此订单');
        };


        $user = User::find($order->user_id);

        if ($user->cant('update', $order)) {
            return $this->api([], false, 402, '你没有权利操作此订单');
        }

        if ($order->status == Order::STATUS_PAY || $order->pay_status == 1) {

            return $this->api(['order' => $order], true, 200, '支付成功');
        }


        $time = Carbon::now();

        if ($channel == 'balance') {

            /*$validator = Validator::make($request->all(), [
                'mobile' => 'required|confirm_mobile_not_change|confirm_rule:mobile_required',
                'code' => 'required|verify_code',
            ]);

            if ($validator->fails()) {
                return $this->api([], false, 400, $validator->errors());
            }*/

            /*if (!Sms::checkCode(\request('mobile'), \request('code'))) {
                return redirect()->back()->withInput(['errors' => $request->input('code')])->withErrors(['errors' => '验证码不正确']);
            }*/

            $sum = Balance::sumByUser($order->user_id);
            if (!is_numeric($sum)) {
                $sum = 0;
            } else {
                $sum = (int)$sum;
            }
            if ($sum < $order->total) {
                return $this->api([], false, 400, '余额不足，请选择其他支付方式');
            }
        }

        try {

            DB::beginTransaction();

            if (!Payment::where('order_id', $order->id)->first()) {
                
                $payment = Payment::create(['order_id' => $order->id, 'channel' => request('channel'),
                    'amount' => $order->total, 'status' => Payment::STATUS_COMPLETED
//                , 'channel_no' => '', 'pingxx_no' => ''
                    , 'paid_at' => Carbon::createFromTimestamp($time->timestamp)]);

                if ($channel == 'balance') {
                    $this->balanceRepository->addRecord(
                        ['user_id' => $order->user_id,
                            'type' => 'shop_order_payment',
                            'note' => '门店订单余额支付：' . $order->total . '来源于订单：' . $order->order_no,
                            'value' => -$order->total,
                            'origin_id' => $payment->id,
                            'origin_type' => 'iBrand\Component\Payment\Models\Payment'
                        ]);

                }

                $order->payments()->save($payment);

                $this->orderProcessor->process($order);

            }

            if ($order->type == Order::TYPE_SHOP AND $order->status == Order::STATUS_PAY) {
                $this->shopOrderProcessor->completeOrder($order);
            }


            DB::commit();

            return $this->api(['order' => $order], true, 200, '支付成功');

        } catch (\Exception $exception) {
            DB::rollBack();
            \Log::info($exception->getMessage() . $exception->getTraceAsString());
            $this->response()->errorInternal($exception->getMessage());
        }

    }


}










